home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / Reference / Amiga_Mail_Vol2 / Archives / Plain / ma91 / boopsi / BoopsiIntro.txt next >
Encoding:
Text File  |  1991-04-15  |  28.7 KB  |  699 lines

  1. (c)  Copyright 1991 Commodore-Amiga, Inc.   All rights reserved.
  2. The information contained herein is subject to change without notice,
  3. and is provided "as is" without warranty of any kind, either expressed
  4. or implied.  The entire risk as to the use of this information is
  5. assumed by the user.
  6.  
  7.  
  8.  
  9.  
  10.  
  11. Introduction to Boopsi
  12.  
  13.  
  14. By John Orr
  15.  
  16.  
  17.  
  18. Boopsi is an acronym for Basic Object Oriented Programming System for 
  19. Intuition.  On its simplest level, boopsi allows the application 
  20. programmer to create Intuition supported gadgets and images with minimal 
  21. overhead.  It allows a program to consolidate gadgets into one entity to 
  22. make processing and updating easy.  On a more sophisticated level, 
  23. boopsi provides ways to create a wide variety of system supported, 
  24. extensible custom gadgets.
  25.  
  26. Understanding boopsi requires an understanding of several of the 
  27. concepts behind Object Oriented Programming (OOP).  This article only 
  28. briefly covers those concepts.  For a more in depth explanation of those 
  29. concepts, see Timothy Budd's book titled A Little Smalltalk (Addison-
  30. Wesley Publishing ISBN 0-201-10698-1).  A port (by Bill Kinnersley) of 
  31. Timothy Budd's Little Smalltalk interpreter is on Fish disk #37.
  32.  
  33. In the boopsi version of the Object Oriented Programming (OOP) model, 
  34. everything is an Object.  Each object is a distinct entity.  Certain 
  35. objects have similar characteristics and can be classified into 
  36. different groups called classes.  As objects, a dog, a cat, and a mouse 
  37. are all distinct objects but they all have something in common; they can 
  38. all be classified as animals.  A specific object is an instance of a 
  39. particular class (``Rover'' is an instance of class ``dog'').
  40.  
  41. Classes can be subdivided into subclasses.  A vegetable object class can 
  42. have several subclasses such as peas, corn, and spinach.  Inversely, the 
  43. superclass of peas, corn, and spinach is ``vegetable''.  In turn, both 
  44. the ``animal'' and ``vegetable'' classes are subclasses.   They are 
  45. subclasses of a universal root category.  The OOP language Smalltalk 
  46. calls this class ``Object''.  
  47.  
  48. In boopsi, the universal root category is called rootclass.  Intuition 
  49. supplies three subclasses of rootclass: gadgetclass, imageclass, and 
  50. icclass.  All boopsi gadgets in the system are an instance of 
  51. gadgetclass.  Likewise, all boopsi images are an instance of imageclass.  
  52. The remaining subclass, icclass, is a concept new to Intuition that 
  53. allow one boopsi object (such as a gadget) to notify another boopsi 
  54. object when some specific event occurs.    For example, a program can 
  55. offer a user two methods of altering one integer value; one by sliding a 
  56. proportional gadget, the other by typing in a value at a string gadget.  
  57. Without boopsi, the program would have to explicitly update one gadget 
  58. when the other was altered by the user.  Using a boopsi icclass object, 
  59. the gadgets can update each other.  The gadgets update each other 
  60. automatically, without the calling program's intervention.
  61.  
  62. The rootclass' subclasses each have their own subclasses.  These 
  63. subclasses are discussed later in this article.  
  64.  
  65. It is possible for an application to create its own custom boopsi class.  
  66. When an application creates a class, it can make it either public or 
  67. private.  A public class has a name associated with it (for example 
  68. gadgetclass) so arbitrary applications can access it.  A private class 
  69. has no name associated with it, so unless an application has a pointer 
  70. to the class, it cannot access it.
  71.  
  72. Each class has a set of methods associated with it  Each method of a 
  73. class is an operation that applies to objects of that class.  A example 
  74. of a method for a class of integers is to add or to subtract "integer'' 
  75. objects.  All boopsi actions are carried out via methods.  
  76.  
  77. In OOP terminology, an application requests an object to perform some 
  78. method by sending the object a message (which is not related to the Exec 
  79. style message).  In boopsi, the amiga.lib function DoMethod() accepts a 
  80. method ID and some method specific parameters (older versions of 
  81. amiga.lib do not have DoMethod(), but the function is available on the 
  82. Atlanta DevCon disks in classface.o).  DoMethod() creates a message from 
  83. these parameters and sends the message to the object:
  84.  
  85.  
  86. ULONG DoMethod(Object *myobject, ULONG MethodID, ...);
  87.  
  88.  
  89. where myobject is a pointer to the target object, MethodID specifies 
  90. which method to perform.  Any remaining parameters are passed on to the 
  91. method in the form of a boopsi message.  Each message contains the 
  92. method ID and the parameters for the method.  The parameters are method 
  93. specific.  For example, one way to delete the imageclass object 
  94. obj2delete is to call the DoMethod() function like this:
  95.  
  96.  
  97. DoMethod(obj2delete, OM_DISPOSE);
  98.  
  99.  
  100. The OM_DISPOSE method does not require any arguments, so, in this case, 
  101. DoMethod() has only two arguments.
  102.  
  103. One peculiar thing about the above function call is that the OM_DISPOSE 
  104. method is not defined for imageclass.  It is instead defined in the 
  105. superclass of imageclass, rootclass.  The OM_DISPOSE method works 
  106. because imageclass inherits the methods of its superclass, rootclass.  
  107. If an object is asked to perform a method that its class does not 
  108. explicitly define, it passes the request onto its superclass for 
  109. processing.  This superclass can in turn pass on the request to its 
  110. superclass if it does not understand the method requested.
  111.  
  112.  
  113. Some of the methods currently defined for Boopsi's rootclass are:
  114.  
  115.  
  116. OM_NEW - Creates a new object.  Normally this method is not called 
  117. directly by the application programmer (a.k.a. using the DoMethod() 
  118. function).  Instead, there is an Intuition function called NewObject() 
  119. that takes care of creating objects.
  120.  
  121.  
  122. APTR NewObject( struct IClass *privateclass, UBYTE *publicclassID, 
  123. unsigned long tag1, ...);
  124.  
  125.  
  126. The privateclass and publicclassID parameters are used to specify the
  127. new object's class. NewObject() only pays attention to one of these.
  128. If privateclass is NULL, publicclassID points to a string naming the
  129. class of the new object.  If privateclass is not NULL, it contains a
  130. pointer to a private class.  The remaining arguments make up a series
  131. of tag ID/data pairs.  These are used to set the object's default
  132. attributes.  These attributes are specific to the class in question.
  133. This function returns a handle to the new object.
  134.  
  135. Each object (or instance of a class) has instance data associated with 
  136. it.  The OM_NEW method takes care of allocating memory for the instance 
  137. data for each class.  Instance data is class specific, but all 
  138. subclasses inherit instance data from their superclasses.  For example, 
  139. part of the instance data for a gadgetclass object is a Gadget 
  140. structure.  Any objects that are instances of subclasses of gadgetclass 
  141. have a Gadget structure embedded in them.  Subclasses can have their own 
  142. class specific instance data in addition to the instance data inherited 
  143. from the superclass.
  144.  
  145. Boopsi gadgetclass and imageclass objects are organized so that 
  146. NewObject() returns a pointer to the corresponding Intuition structure 
  147. embedded within them (struct Gadget and struct Image, respectively).  
  148. This makes it possible to use non-boopsi Intuition functions on boopsi 
  149. objects.  Normally, these internal structures should be considered 
  150. private, and should be accessed through the corresponding attributes, 
  151. but if it is necessary, an application can look at certain fields in the 
  152. embedded structure.  For both gadgets and images, the Left, Top, Width, 
  153. and Height fields are legal to look at.  The Images NextImage field is 
  154. also OK for viewing.  However, this does not mean that it is OK for an 
  155. application to go poking around the internals of boopsi objects.  All 
  156. boopsi objects are strictly private and can change without notice.  Use 
  157. only the functions Intuition provides for manipulating boopsi objects.
  158.  
  159. Another function, NewObjectA(), works exactly like NewObject(), but 
  160. instead of accepting the tag pairs as arguments, it accepts a single 
  161. pointer to a TagList.  See the Intuition Autodocs for more details.
  162.  
  163.  
  164.  
  165. OM_DISPOSE - Deletes an object.  Like OM_NEW this method is not normally 
  166. called directly by the application program.  Instead there is an 
  167. Intuition function DisposeObject() that takes care of object disposal.
  168.  
  169.  
  170. void DisposeObject( APTR object2delete );
  171.  
  172.  
  173.  
  174. OM_SET - Sets object specific attributes.  This method is not normally 
  175. called by the application program directly.  Instead, there are two 
  176. Intuition functions that set object attributes:
  177.  
  178.  
  179. ULONG SetAttrs( APTR object, unsigned long tag1, ... );
  180.  
  181. ULONG SetGadgetAttrs( struct Gadget *mygadgetobject, struct Window 
  182. *window, struct Requester *requester, unsigned long tag1, ... );
  183.  
  184.  
  185. SetAttrs() accepts as arguments a pointer to the object in question and 
  186. a series of tag pairs corresponding to the attributes to set.  
  187. SetGadgetAttrs() is a special version of SetAttrs() that is required to 
  188. change the attributes of gadgetclass objects.  SetGadgetAttrs() is 
  189. similar to SetAttrs(), except it has some extra parameters that a gadget 
  190. needs to redraw itself in response to the attribute changes.  This 
  191. function can be used on non-gadgetclass objects as the gadget specific 
  192. parameters are ignored by the other object classes.  If the gadget is 
  193. not yet attached to a window or requester, these arguments should be set 
  194. to NULL. 
  195.  
  196. Both of these functions have corresponding TagList based arguments, 
  197. SetAttrsA() and SetGadgetAttrs().
  198.  
  199.  
  200.  
  201. OM_GET - Reads an object specific attribute.  The Intuition function 
  202. GetAttr() provides easy access to this method:
  203.  
  204.  
  205. ULONG GetAttr( unsigned long attrID, APTR object, ULONG *storagePtr );
  206.  
  207.  
  208. GetAttr() fills in storagePtr with the value of the object's attribute 
  209. attrID.  The function returns FALSE if there is an error.
  210.  
  211.  
  212.  
  213. OM_ADDMEMBER - Adds a boopsi object to another object's list, if it has 
  214. one.  Certain object classes have an Exec list as part of their instance 
  215. data.  To add the object object2add to the list of the object mainobject 
  216. use DoMethod() like so:
  217.  
  218.  
  219. DoMethod(mainobject, OM_ADDMEMBER, object2add);
  220.  
  221.  
  222. DoMethod() also has a non-varargs form called DM() (also in amiga.lib).  
  223. DM() accepts an object pointer and a pointer to a structure specific to 
  224. a method.  For example, the DM() form of the above DoMethod() call would 
  225. look like this:
  226.  
  227.  
  228. DM(mainobject, addmemstruct);
  229.  
  230.  
  231. where addmemstruct is a pointer to the following structure (defined in 
  232. <intuition/classusr.h>):
  233.  
  234.  
  235.  
  236. struct opMember {
  237.     ULONG     MethodID;      /* in this case MethodID = OM_ADDMEMBER */
  238.     Object    *opam_Object;  /* = addmemstruct */
  239.  
  240. };
  241.  
  242.  
  243. OM_REMMEMBER - Removes a boopsi object previously added with 
  244. OM_ADDMEMBER.  The parameters are the same for OM_ADDMEMBER.
  245.  
  246.  
  247. OM_UPDATE - Updates attributes of an object.  For gadgets, this method 
  248. is very similar to the OM_SET method.  It is normally used only between 
  249. objects for notifying each other of attribute changes, so simple boopsi 
  250. users should use the SetAttrs() and SetGadgetAttrs() functions.
  251.  
  252.  
  253. OM_NOTIFY - Notifies one object when another object's attribute(s) have 
  254. changed.  It is normally used only between objects for modifying each 
  255. others attributes, so simple boopsi users should use the SetAttrs() and 
  256. SetGadgetAttrs() functions.
  257.  
  258.  
  259.  
  260. Attributes
  261.  
  262.  
  263. All boopsi objects have attributes associated with them.  These 
  264. attributes reflect various properties of a specific object.  For 
  265. example, an image object has attributes such as IA_Left, IA_Top, 
  266. IA_Width, and IA_Height, all of which correspond to fields in the Image 
  267. structure.  Five methods deal with an object's attributes:
  268.  
  269.  
  270. OM_NEW sets attributes at object creation (initialization) time
  271. OM_SET changes attributes after the object has been created
  272. OM_GET reads an object attribute
  273. OM_UPDATE updates an object attribute (for use by objects only)
  274. OM_NOTIFY notifies one object of changes to another object's attributes
  275.  
  276. Not all of these methods apply to all attributes.  Some attributes are 
  277. not ``settable'' or not ``gettable'', for example.   See the appendix at 
  278. the end of this article to find out which of these methods apply to 
  279. specific attributes.
  280.  
  281.  
  282.  
  283.  
  284. Imageclass Subclasses
  285.  
  286.  
  287. An imageclass object contains an Image structure that Intuition uses to 
  288. render objects such as gadgets.  Boopsi imageclass objects are organized 
  289. so that when NewObject() returns a pointer to an imageclass object, it 
  290. points to the actual Image structure.  
  291.  
  292. Normally, an application does not create an imageclass object.  Instead, 
  293. it will use a subclass of imageclass.  Currently, there are four 
  294. subclasses:  frameiclass, sysiclass, fillrectclass, and itexticlass.
  295.  
  296. frameiclass - An embossed or recessed rectangular frame, rendered in the 
  297. proper DrawInfo pens, with enough intelligence to bound or center its 
  298. contents.
  299.  
  300. sysiclass - The class of system images.  The class includes all the 
  301. images for the system gadgets, and the Gadtools check mark and button 
  302. glyphs.
  303.  
  304. fillrectclass - Rectangle with frame and pattern support.
  305.  
  306. itexticlass - A specialized image class used for rendering text.  Note 
  307. that you have to calculate itexticlass object's width and height 
  308. yourself.
  309.  
  310.  
  311.  
  312.  
  313.  
  314. Gadgetclass Subclasses
  315.  
  316.  
  317. A gadgetclass object contains an Intuition Gadget structure.  Like 
  318. imageclass, applications do not normally create objects of this class, 
  319. but instead create objects of subclasses of gadgetclass.  Currently, 
  320. gadgetclass has four subclasses:
  321.  
  322.  
  323. propgclass - An easy to use, one-dimensional proportional gadget.
  324.  
  325. strgclass - A string gadget.
  326.  
  327. groupgclass - A special gadget class that creates one composite gadget 
  328. out of several others.
  329.  
  330. buttongclass - A repeating boolean button gadget.
  331.  
  332.  
  333.  
  334. buttongclass has a subclass of its own:
  335.  
  336.  
  337.  
  338. frbuttongclass - A button that outlines its label with a frame.
  339.  
  340.  
  341.  
  342. The example boopsi1.c ( at the end of this article) uses sysiclass 
  343. images and several boopsi gadgets.  The example takes care of processing 
  344. and updating the gadgets.  
  345.  
  346.  
  347.  
  348.  
  349. Interconnection
  350.  
  351.  
  352. The boopsi gadgets in boopsi1.c are not very powerful.  The gadgets work 
  353. independently of each other, forcing the application to unify them.  It 
  354. is possible to make gadget objects update each other without the 
  355. application's intervention.
  356.  
  357. Gadgetclass defines two attributes used in this updating process: 
  358. ICA_Target and ICA_Map.  The ICA_Target attribute specifies a pointer to 
  359. a target object.  If an object's attribute changes (and the OM_NOTIFY 
  360. method applies to that attribute), the object sends itself an OM_NOTIFY 
  361. message.  If the object has a target object, the target will receive an 
  362. OM_UPDATE message which usually tells the target to set one of its own 
  363. attributes.  For example, when the user slides the knob of a propgclass 
  364. object, its PGA_Top attribute changes.  If this object has a second 
  365. propgclass object as its target, the second object will receive an 
  366. OM_UPDATE message and will set its corresponding PGA_Top attribute to 
  367. the PGA_Top value of the first propgclass object.
  368.  
  369. Because objects of different classes do not always have corresponding 
  370. attributes, there is a way to map attributes of one object to the 
  371. attributes of another.  The ICA_Map accepts a TagItem array of attribute 
  372. pairs.  The first entry in the pair is the source attribute ID and the 
  373. second is the target object's attribute.  For example, an ICA_Map that 
  374. maps a prop gadget's PGA_Top attribute to a string gadget's 
  375. STRINGA_LongVal attribute would look like this:
  376.  
  377.  
  378. struct TagItem slidertostring[] = {
  379.     {PGA_Top, STRINGA_LongVal},
  380.     {TAG_END, }
  381. };
  382.  
  383.  
  384. Note that the OM_UPDATE method has to apply to the target attribute for 
  385. the change to take place.
  386.  
  387. Although the gadget attributes ICA_Target and ICA_Map allow boopsi 
  388. gadgets to update each other, by themselves these attributes do not 
  389. provide the application with any information on changes to the gadgets.  
  390. Instead of using another gadget as a target object, an object targets an 
  391. icclass object.  Icclass  (or InterConnection) objects are simple 
  392. information forwarders.
  393.  
  394. Icclass defines two attributes: ICA_Target and ICA_Map, which are almost 
  395. identical to the gadgetclass attributes.  The difference is that icclass 
  396. objects can send the application an IDCMPUPDATE IntuiMessage when it 
  397. receives an OM_UPDATE.  If an icclass object receives an OM_UPDATE, it 
  398. will send the IntuiMessage only if the icclass object's ICA_Target is 
  399. ICTARGET_IDCMP and the updated attribute is mapped to a special dummy 
  400. attribute, ICSPECIAL_CODE.  The IntuiMessage's Code field contains the 
  401. lower 16 bits of the updated attribute.
  402.  
  403. Icclass has a more powerful subclass called modelclass.  A modelclass 
  404. object sends OM_UPDATE messages to an entire list of objects that the 
  405. modelclass object maintains.  This makes it possible for gadgets to 
  406. update each other and for the application to find out about the changes.  
  407. A modelclass object ``broadcasts'' attribute changes to its list of 
  408. boopsi objects and it also lets the application know about attribute 
  409. changes because it inherits the ICTARGET_IDCMP mechanism from icclass.  
  410. To add objects to a modelclass object's list, use the OM_ADDMEMBER 
  411. method.
  412.  
  413. The power of icclass and modelclass lies in using them to create a 
  414. custom subclass.  Consider a group of prop gadgets each of which is used 
  415. to control one of a color's R, G, B, H, S, and V components.  When the 
  416. user changes one of the color components with a prop gadget, the custom 
  417. model will be notified of that change and, because it is customized for 
  418. this specific purpose, it will recalculate the values for the remaining 
  419. components.   The model will then let the rest of the prop gadget 
  420. objects (which are attached to icclass objects in the custom model's 
  421. personal list) know about the changes to their component values so they 
  422. can move their slider to its new position.  All this work is done by the 
  423. objects themselves; the application does not have to process any of the 
  424. intermediate input.
  425.  
  426. In general, boopsi's power lies in its Intuition-supported 
  427. extensibility.  Using the existing boopsi classes as a foundation,  you 
  428. can create entirely new subclasses.  This makes it possible to create 
  429. your own custom gadgetry and have it work perfectly with Intuition, just 
  430. like any existing gadget.   New subclasses of modelclass can be used to 
  431. create gadgets that talk directly to ARexx or the clipboard device.  If 
  432. new classes are general enough, they can be made public so other 
  433. applications can use them.
  434.  
  435.  
  436. =====================================================================
  437.  
  438.  
  439. ;/* boopsi1.c - Execute me to compile me with Lattice 5.10a
  440. LC -b1 -cfistq -v -y -j73 boopsi1.c
  441. Blink FROM LIB:c.o,boopsi1.o TO boopsi1 LIBRARY LIB:LC.lib,LIB:Amiga.lib
  442. quit
  443. */
  444.  
  445. /* boopsi example showing simple creation of boopsi
  446. ** gadgets and using system images.
  447. */
  448.  
  449. #include <intuition/intuition.h>
  450. #include <intuition/classusr.h>
  451. #include <intuition/imageclass.h>
  452. #include <intuition/gadgetclass.h>
  453. #include <clib/exec_protos.h>
  454. #include <clib/intuition_protos.h>
  455. #include <clib/graphics_protos.h>
  456.  
  457. #ifdef LATTICE
  458. int CXBRK(void) { return(0); }  /* Disable Lattice CTRL/C handling */
  459. int chkabort(void) { return(0); }
  460. #endif
  461.  
  462. UBYTE *vers = "\0$VER: boopsi1 1.0";
  463.  
  464. void ProcessWindow(void);
  465.  
  466. #define MYPROP       1L
  467. #define MYSTRING     2L
  468. #define MYLEFTBUT    3L
  469. #define MYRIGHTBUT   4L
  470.  
  471. #define GADTOP      10L
  472. #define STRLEFT     20L
  473. #define STRWIDTH    30L
  474. #define STRHEIGHT   11L
  475. #define INITVALUE   25L
  476. #define PROPWIDTH   100L
  477. #define PROPVIS     10L
  478. #define BUTGADWID   11L
  479. #define BUTGADHEI   11L
  480.  
  481. struct Screen *screen;
  482. struct Window *window;
  483. struct DrawInfo *drinfo;
  484. struct Library *IntuitionBase;
  485. struct Gadget *prop, *string, *leftbut, *rightbut, *mygadgets;
  486. struct Image *rightbimage, *leftbimage;
  487.  
  488.  
  489.  
  490. void main(void)
  491. {
  492.     struct Gadget *tmpgad;
  493.     WORD gadtop;
  494.     
  495.     tmpgad = (struct Gadget *)&mygadgets;
  496.  
  497.     if (IntuitionBase = OpenLibrary("intuition.library", 36L))
  498.     {
  499.         if (screen = LockPubScreen(NULL))
  500.         {
  501.             /* need my screen's DrawInfo for the system gadget images */
  502.             drinfo = GetScreenDrawInfo(screen);
  503.  
  504.             gadtop = screen->Font->ta_YSize + GADTOP;
  505.             if (window = OpenWindowTags(NULL,
  506.                     WA_Title, (ULONG *)"AMail boopsi1",
  507.                     WA_Height, gadtop+STRHEIGHT+10L,
  508.                     WA_Width,  STRLEFT+STRWIDTH+PROPWIDTH+2*BUTGADWID+15,
  509.                     WA_Flags, WFLG_DEPTHGADGET | WFLG_DRAGBAR | WFLG_CLOSEGADGET,
  510.                     WA_IDCMP, IDCMP_CLOSEWINDOW | IDCMP_GADGETUP,
  511.                             TAG_END))
  512.             {
  513.     
  514.                 /* Create a boopsi string gadget */
  515.                 if (string = (struct Gadget *)NewObject(NULL, "strgclass",
  516.                             /* All the normal Gadget fields */
  517.                             GA_ID,              MYSTRING,
  518.                             GA_Immediate,           TRUE,
  519.                             GA_RelVerify,           TRUE,
  520.                             GA_Top,             gadtop,
  521.                             GA_Left,            STRLEFT,
  522.                             GA_Width,           STRWIDTH,
  523.                             GA_Height,          STRHEIGHT,
  524.                             STRINGA_MaxChars,   3,
  525.                             STRINGA_LongVal,    INITVALUE,
  526.                             STRINGA_Justification, STRINGRIGHT,
  527.                             
  528.                             /* Boopsi makes it easy to link gadgets together.
  529.                             ** The GA_Previous tag accepts a (struct Gadget **)
  530.                             ** to the previous gadget in the list, then changes
  531.                             ** this value to point to the gadget being 
  532.                             ** created (in this case, "string").
  533.                             */
  534.                             GA_Previous,        tmpgad,
  535.                             TAG_END))
  536.                 {
  537.                     /* create the prop gadget */
  538.                     if (prop = (struct Gadget *)NewObject(NULL, "propgclass",
  539.                                 GA_Immediate,   TRUE,
  540.                                 GA_RelVerify,   TRUE,
  541.                                 PGA_Freedom,    FREEHORIZ,
  542.                                 PGA_Borderless, FALSE,
  543.                                 GA_Left,        STRLEFT + STRWIDTH,
  544.                                 GA_Top,         gadtop,
  545.                                 GA_Height,      BUTGADHEI,
  546.                                 PGA_Top,        INITVALUE,
  547.                                 PGA_Visible,    PROPVIS,
  548.                                 PGA_Total,      PROPWIDTH,
  549.                                 GA_ID,          MYPROP,
  550.                                 
  551.                                 /* link prop to string and 
  552.                                 ** make tmpgad point to prop. */
  553.                                 GA_Previous,    tmpgad,
  554.                                 TAG_END))
  555.                     {
  556.                         /* Ask the system for a left arrow image 
  557.                         ** for the left arrow gadget. */
  558.                         if (leftbimage = (struct Image *)NewObject(NULL, 
  559.                             "sysiclass", 
  560.                             
  561.                             /* boopsi needs this screen's DrawInfo
  562.                             ** structure to get the right image.  */
  563.                             SYSIA_DrawInfo,   drinfo,
  564.                             SYSIA_Which,      LEFTIMAGE,
  565.                             
  566.                             /* this will give us 11 x 11 buttons */
  567.                             SYSIA_Size,       SYSISIZE_MEDRES,
  568.                                   TAG_END))
  569.                         {
  570.                             /* Now ask for a right arrow */
  571.                             if (rightbimage = (struct Image *)NewObject(NULL, 
  572.                                 "sysiclass", 
  573.                                 SYSIA_DrawInfo,   drinfo,
  574.                                 SYSIA_Which,      RIGHTIMAGE,
  575.                                 SYSIA_Size,       SYSISIZE_MEDRES,
  576.                                               TAG_END))
  577.                             {
  578.                                 /* Create the left button */
  579.                                 if (leftbut = (struct Gadget *)NewObject(NULL, 
  580.                                     "buttongclass",
  581.                                     GA_ID,        MYLEFTBUT,
  582.                                     GA_Immediate, TRUE,
  583.                                     GA_RelVerify, TRUE,
  584.                                     GA_Image,     leftbimage,
  585.                                     GA_Top,       gadtop,
  586.                                     GA_Left,      STRLEFT+STRWIDTH+PROPWIDTH-15,
  587.                                     GA_Width,     BUTGADWID,
  588.                                     GA_Height,    BUTGADHEI,
  589.                                     GA_Previous,  tmpgad,
  590.                                     TAG_END))
  591.                                 {
  592.                                     /* Create the right button */
  593.                                     if (rightbut = (struct Gadget *)NewObject(NULL, 
  594.                                         "buttongclass",
  595.                                         GA_ID,        MYRIGHTBUT,
  596.                                         GA_Immediate, TRUE,
  597.                                         GA_RelVerify, TRUE,
  598.                                         GA_Image,     rightbimage,
  599.                                         GA_Top,       gadtop,
  600.                                         GA_Left,      
  601.                                             STRLEFT+STRWIDTH+PROPWIDTH+BUTGADWID-10,
  602.                                         GA_Width,     BUTGADWID,
  603.                                         GA_Height,    BUTGADHEI,
  604.                                         GA_Previous,  tmpgad,
  605.                                         TAG_END))
  606.                                     {
  607.                                         /* All of the gadgets have been created 
  608.                                         ** and linked together.  Add them to the
  609.                                         ** display and display them.
  610.                                         */
  611.                                         AddGList(window, mygadgets, -1, -1, NULL);
  612.                                         RefreshGList(mygadgets, window, NULL, -1);
  613.                                         ProcessWindow();
  614.                                         RemoveGList(window, mygadgets, -1);
  615.                                         DisposeObject(rightbut);
  616.                                     }
  617.                                     DisposeObject(leftbut);
  618.                                 }
  619.                                 DisposeObject(rightbimage);
  620.                             }
  621.                             DisposeObject(leftbimage);
  622.                         }
  623.                         DisposeObject(prop);
  624.                     }
  625.                     DisposeObject(string);
  626.                 }
  627.                 CloseWindow(window);
  628.             }
  629.             FreeScreenDrawInfo(screen, drinfo);
  630.             UnlockPubScreen(NULL, screen);
  631.         }
  632.         CloseLibrary(IntuitionBase);
  633.     }
  634. }
  635.  
  636. void ProcessWindow(void)
  637. {
  638.     struct IntuiMessage *imsg;
  639.     BOOL returnvalue = TRUE;
  640.     ULONG class;
  641.     LONG currval = INITVALUE;
  642.     struct Gadget *g;
  643.     
  644.     
  645.     while (returnvalue)
  646.     {
  647.         WaitPort(window->UserPort);
  648.         while (imsg = (struct IntuiMessage *)GetMsg(window->UserPort))
  649.         {
  650.             g = (struct Gadget *)imsg->IAddress;
  651.             class = imsg->Class;
  652.             ReplyMsg((struct Message *)imsg);
  653.             switch (class)
  654.             {
  655.                 case IDCMP_CLOSEWINDOW:
  656.                     returnvalue = FALSE;
  657.                     break;
  658.                 case IDCMP_GADGETUP:
  659.                     switch (g->GadgetID)
  660.                     {
  661.                         case MYLEFTBUT:
  662.                             currval--;
  663.                             break;
  664.                         case MYRIGHTBUT:
  665.                             currval++;
  666.                             break;
  667.                         case MYPROP:
  668.                             /* read the prop gadget's value */
  669.                             GetAttr(PGA_TOP, prop, &currval);
  670.                             break;
  671.                         case MYSTRING:
  672.                             /* read the string gadget's value */
  673.                             GetAttr(STRINGA_LongVal, string, &currval);
  674.                             break;
  675.                     }
  676.                     /* make sure the value is between 0 and 90 */
  677.                     if (currval < 0L)
  678.                         currval = 0L;
  679.                     else
  680.                         if (currval > PROPWIDTH - PROPVIS) 
  681.                             currval = PROPWIDTH - PROPVIS;
  682.                     
  683.                     /* Update the values of the prop and string.
  684.                     ** gadgets (Intuition takes care of the  refresh). */
  685.                     
  686.                     SetGadgetAttrs( prop, window, NULL, 
  687.                                     PGA_TOP, currval,
  688.                                 TAG_END );
  689.  
  690.                     SetGadgetAttrs( string, window, NULL, 
  691.                                 STRINGA_LongVal, currval,
  692.                                     TAG_END );
  693.  
  694.                     break;
  695.             }
  696.         }
  697.     }
  698. }
  699.